home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / TELNET.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-18  |  13.4 KB  |  613 lines

  1. /* Internet Telnet client
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. /* Mods by PA0GRI */
  5. /* Mods by KO4KS */
  6. #ifdef MSDOS
  7. #include <conio.h>
  8. #endif
  9. #include "global.h"
  10. #include "commands.h"
  11. #include "mbuf.h"
  12. #include "socket.h"
  13. #include "telnet.h"
  14. #include "netuser.h"
  15. #include "usock.h"
  16.  
  17. #if !defined(_lint)
  18. static char rcsid[] OPTIONAL = "$Id: telnet.c,v 1.23 1997/08/19 01:19:22 root Exp root $";
  19. #endif
  20.  
  21. #if !defined(TNOS_68K) && !defined(UNIX)
  22. void displayStatLine (int offset, int phase, int onlymarquee);
  23. extern unsigned char SCREENwidth, SCREENlength;
  24. #endif
  25.  
  26. #ifdef CONVERS
  27. extern char CConsole[];
  28. #endif
  29.  
  30. static void dontopt (struct telnet *tn,int opt);
  31. static void tel_output (int unused,void *p1,void *p2);
  32. static void answer (struct telnet *tn,int r1,int r2);
  33. static int filemode (FILE * fp, int mode);
  34. static void doopt (struct telnet *tn,int opt);
  35. static void willopt (struct telnet *tn,int opt);
  36. static void wontopt (struct telnet *tn,int opt);
  37.  
  38. #ifndef CTLZ
  39. #define    CTLZ    26
  40. #endif
  41.  
  42. static int Refuse_echo = 0;
  43. static int Tn_cr_mode = 0;            /* if true turn <cr> to <cr-nul> */
  44. static int usesplit = 0;        /* kludge for doconf */
  45.  
  46. static char *conversinit;
  47.  
  48.  
  49. #ifdef    DEBUG
  50. char *T_options[] =
  51. {
  52.     "Transmit Binary",
  53.     "Echo",
  54.     "",
  55.     "Suppress Go Ahead",
  56.     "",
  57.     "Status",
  58.     "Timing Mark"
  59. };
  60. #endif
  61.  
  62.  
  63.  
  64. #ifdef    MAILBOX
  65. /* Execute user BBS command */
  66. int
  67. dobbs (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
  68. {
  69. struct session *sp;
  70. struct sockaddr_in fsocket;
  71.  
  72.     /*Make sure this comes from console - WG7J*/
  73.     if (Curproc->input != Command->input)
  74.         return 0;
  75.  
  76.     /* Allocate a session descriptor */
  77.     if ((sp = newsession ("Local PBBS access", TELNET, 0)) == NULLSESSION) {
  78.         tputs (TooManySessions);
  79.         return 1;
  80.     }
  81.     chname (Curproc, "Local PBBS access");
  82.     fsocket.sin_family = AF_INET;
  83.     fsocket.sin_port = IPPORT_TELNET;
  84.  
  85.     fsocket.sin_addr.s_addr = 0x7f000001L;    /* 127.0.0.1 the loopback interface */
  86.     if ((sp->s = socket (AF_INET, SOCK_STREAM, 0)) == -1) {
  87.         tputs (Nosock);
  88.         (void) keywait (NULLCHAR, 1);
  89.         freesession (sp);
  90.         return 1;
  91.     }
  92.     return tel_connect (sp, (char *) &fsocket, SOCKSIZE);
  93. }
  94. #endif /*MAILBOX*/
  95.  
  96.  
  97.  
  98.  
  99. #ifdef RLOGINSERV
  100. /* Execute remote login command */
  101. int
  102. dorlogin (int argc OPTIONAL, char *argv[], void *p)
  103. {
  104.     free (argv[0]);
  105.     argv[0] = strdup ("telnet");
  106.     if (argv[2])
  107.         free (argv[2]);
  108.     argv[2] = strdup ("513");
  109.     if (!argv[1])
  110.         argv[1] = strdup (Hostname);
  111.     usesplit = 1;
  112.     return dotelnet (3, argv, p);
  113. }
  114. #endif
  115.  
  116.  
  117.  
  118. #ifdef ALLSESSIONS
  119. #ifdef CONVERS
  120. /* Execute user conference command */
  121. int
  122. doconf (int argc OPTIONAL, char *argv[], void *p)
  123. {
  124. char buf[32], buf2[96];
  125. char *cptr;
  126.  
  127.     if (CConsole[0])
  128.         (void) strlwr (CConsole);    /* just in case */
  129.  
  130.     sprintf (buf, "/NA %s %s\n", (CConsole[0]) ? CConsole : "sysop", (argc > 2 && argv[2]) ? argv[2] : "-1");
  131.  
  132.     free (argv[0]);
  133.     argv[0] = strdup ("telnet");
  134.  
  135.     if (argc > 1 && !argv[1])    {
  136.         strncpy (buf2, Hostname, 96);
  137.         cptr = strchr (buf2, '.');
  138.         if (cptr)
  139.             *cptr = 0;
  140.         (void) strlwr (buf2);
  141.         argv[1] = strdup (buf2);
  142.     }
  143.  
  144.     if (argc > 2 && argv[2])
  145.         free (argv[2]);
  146.     argv[2] = strdup ("3600");
  147.  
  148.     conversinit = buf;        /*lint !e789 */
  149.     usesplit = 1;
  150.     return dotelnet (3, argv, p);
  151. }
  152. #endif /* CONVERS */
  153.  
  154.  
  155. #ifdef ALLSERV
  156. extern void clrchatline (struct session * sp);
  157. #endif
  158.  
  159. /* Execute user telnet command */
  160. int
  161. dotelnet (int argc, char *argv[], void *p OPTIONAL)
  162. {
  163. struct session *sp;
  164. struct sockaddr_in fsocket;
  165. int split;
  166.  
  167.     split = usesplit;
  168.     usesplit = 0;
  169.  
  170.     /*Make sure this comes from console - WG7J*/
  171.     if (Curproc->input != Command->input)
  172.         return 0;
  173.  
  174. #ifdef ALLSERV
  175.     if ((strlen (argv[0]) > 1) && (argv[0][1] == 't'))    /* tty-link command */
  176.         split = 1;
  177. #endif
  178.  
  179.     /* Allocate a session descriptor */
  180.     if ((sp = newsession (argv[1], TELNET, split)) == NULLSESSION) {
  181.         tputs (TooManySessions);
  182.         return 1;
  183.     }
  184.     fsocket.sin_family = AF_INET;
  185.     if (argc < 3) {
  186.         if (split)
  187.             fsocket.sin_port = IPPORT_TTYLINK;
  188.         else
  189.             fsocket.sin_port = IPPORT_TELNET;
  190.     } else
  191.         fsocket.sin_port = (int16) atoip (argv[2]);
  192.  
  193.     tprintf ("Resolving %s... ", sp->name);
  194.     if ((fsocket.sin_addr.s_addr = resolve (sp->name)) == 0) {
  195.         tprintf (Badhost, sp->name);
  196.         (void) keywait (NULLCHAR, 1);
  197.         freesession (sp);
  198.         return 1;
  199.     }
  200.     if ((sp->s = socket (AF_INET, SOCK_STREAM, 0)) == -1) {
  201.         tputs (Nosock);
  202.         (void) keywait (NULLCHAR, 1);
  203.         freesession (sp);
  204.         return 1;
  205.     }
  206.     return tel_connect (sp, (char *) &fsocket, SOCKSIZE);
  207. }
  208. #endif
  209.  
  210.  
  211.  
  212. /* Generic interactive connect routine, used by Telnet, AX.25, NET/ROM */
  213. int
  214. tel_connect (struct session *sp, char *fsocket, int len)
  215. {
  216. unsigned int theindex;
  217. struct telnet tn;
  218.  
  219.     theindex = (unsigned int) (sp - Sessions);
  220.     memset ((char *) &tn, 0, sizeof (tn));
  221.     tn.eolmode = (char) Tn_cr_mode;
  222.     tn.session = sp;    /* Upward pointer */
  223.     sp->cb.telnet = &tn;    /* Downward pointer */
  224.     (void) sockmode (sp->s, SOCK_ASCII);    /* Default to ascii mode */
  225.  
  226.     /* place the initial cursor in the input area of split screens */
  227. #ifdef ALLSERV
  228.     if (sp->split) {
  229.         clrchatline (sp);
  230.         clrscr ();
  231.     }
  232. #endif
  233.  
  234.     tprintf ("Trying %s...\n", psocket ((struct sockaddr *) fsocket));
  235.     if (connect (sp->s, fsocket, len) == -1) {
  236.         tprintf ("%s session %u failed: %s errno %d\n",
  237.               Sestypes[sp->type], theindex, sockerr (sp->s), errno);
  238.  
  239.         (void) keywait (NULLCHAR, 1);
  240.         freesession (sp);
  241.         return 1;
  242.     }
  243.     tprintf ("%s session ", Sestypes[sp->type]);
  244.     tprintf ("%u connected to %s\n", theindex, sp->name);
  245.     tnrecv (&tn);
  246.     return 0;
  247. }
  248.  
  249.  
  250.  
  251. /* Telnet input routine, common to both telnet and ttylink */
  252. void
  253. tnrecv (struct telnet *tn)
  254. {
  255. int c, s, theindex;
  256. struct session *sp;
  257. char const *cp;
  258. #if !defined(TNOS_68K) && !defined(UNIX)
  259. struct text_info tr;
  260. unsigned char attr;
  261. #endif
  262. #ifdef LZW
  263. int bits, mode;
  264. struct usock *up;
  265. #endif
  266.  
  267.     sp = tn->session;
  268.     s = sp->s;
  269.  
  270.     theindex = sp - Sessions;
  271.  
  272.     /* Fork off the transmit process */
  273.     sp->proc1 = newproc ("tel_out", 1024, tel_output, 0, tn, NULL, 0);
  274.  
  275.     /* Process input on the connection */
  276.     while ((c = recvchar (s)) != EOF) {
  277.         if (c != IAC) {
  278.             tputc (uchar(c));
  279.             continue;
  280.         }
  281.         /* IAC received, get command sequence */
  282.         c = recvchar (s);
  283.         switch (c) {
  284.             case WILL:
  285.                 c = recvchar (s);
  286.                 willopt (tn, c);
  287.                 break;
  288.             case WONT:
  289.                 c = recvchar (s);
  290.                 wontopt (tn, c);
  291.                 break;
  292.             case DO:
  293.                 c = recvchar (s);
  294.                 doopt (tn, c);
  295.                 break;
  296.             case DONT:
  297.                 c = recvchar (s);
  298.                 dontopt (tn, c);
  299.                 break;
  300. #ifdef LZW
  301.             case COMPRESSED:
  302.                 mode = recvchar (s);
  303.                 bits = recvchar (s);
  304.                 mode = (mode == 'f') ? 1 : 0;
  305.                 if (bits < 9 || bits > 16)
  306.                     break;
  307.                 if ((up = itop (s)) == NULLUSOCK)
  308.                     break;
  309.                 if (up->zout == NULLLZW)
  310.                     lzwinit (s, bits, mode);
  311.                 else
  312.                     lzwfree (up);
  313.                 break;
  314. #endif
  315.             case CLEARSCREEN:
  316. #if !defined(TNOS_68K) && !defined(UNIX)
  317.                 if (!sp->split) {
  318.                     window (1, 1, SCREENwidth, SCREENlength);
  319.                     clrscr ();    /* clear the screen */
  320.                     window (1, SCREENlength - 1, SCREENwidth, SCREENlength);    /* changed 1,1->1,24 */
  321.                     gettextinfo (&tr);
  322.                     attr = ((tr.attribute & 0x0f) << 4) + ((tr.attribute & 0x70) >> 4);
  323.                     textattr (attr);
  324.                     clrscr ();
  325.                     cputs ("_\b");
  326.                     window (1, 1 + sp->screen->statline, SCREENwidth, SCREENlength - 2);
  327.                     textattr (tr.attribute);
  328.                     sp->split = 1;
  329.                     if (sp->screen->statline)
  330.                         displayStatLine (0, 1, 0);
  331.                 }
  332. #endif
  333.                 break;
  334.             case CLEARSPLIT:
  335. #if !defined(TNOS_68K) && !defined(UNIX) && defined(ALLSERV)
  336.                 clrchatline (sp);
  337. #endif
  338.                 break;
  339.             case IAC:    /* Escaped IAC */
  340.                 tputc (IAC);
  341.                 break;
  342.             default:
  343.                 break;
  344.         }
  345.     }
  346.     /* A close was received from the remote host.
  347.      * Notify the user, kill the output task and wait for a response
  348.      * from the user before freeing the session.
  349.      */
  350.     (void) sockmode (sp->output, SOCK_ASCII);    /* Restore newline translation */
  351.     cp = sockerr (s);
  352.     tprintf ("%s session %u", Sestypes[sp->type], theindex);
  353.     tprintf (" closed: %s\n", cp != NULLCHAR ? cp : "EOF");
  354.     killproc (sp->proc1);
  355.     sp->proc1 = NULLPROC;
  356.     close_s (sp->s);
  357.     sp->s = -1;
  358.     (void) keywait (NULLCHAR, 1);
  359.     freesession (sp);
  360. }
  361.  
  362.  
  363.  
  364. /* User telnet output task, started by user telnet command */
  365. static void
  366. tel_output (int unused OPTIONAL, void *tn1, void *p OPTIONAL)
  367. {
  368. struct session *sp;
  369. int c;
  370. struct telnet *tn;
  371.  
  372.     tn = (struct telnet *) tn1;
  373.     sp = tn->session;
  374.  
  375.     if (conversinit) {
  376.         usprintf (sp->s, conversinit);
  377.         conversinit = 0;
  378.     }
  379.     /* Send whatever's typed on the terminal */
  380.     while ((c = recvchar (sp->input)) != EOF) {
  381.         usputc (sp->s, uchar(c));
  382.         if (!tn->remote[TN_ECHO] && sp->record != NULLFILE)
  383.             (void) putc (c, sp->record);
  384.  
  385.         /* By default, output is transparent in remote echo mode.
  386.          * If eolmode is set, turn a cr into cr-null.
  387.          * This can only happen when in remote echo (raw) mode, since
  388.          * the tty driver normally maps \r to \n in cooked mode.
  389.          */
  390.         if (c == '\r' && tn->eolmode)
  391.             usputc (sp->s, '\0');
  392.  
  393.         if (tn->remote[TN_ECHO])
  394.             usflush (sp->s);
  395.     }
  396.     /* Make sure our parent doesn't try to kill us after we exit */
  397.     sp->proc1 = NULLPROC;
  398. }
  399.  
  400.  
  401.  
  402. int
  403. doechomode (int argc, char *argv[], void *p OPTIONAL)
  404. {
  405.     if (argc < 2) {
  406.         if (Refuse_echo)
  407.             tputs ("Refuse\n");
  408.         else
  409.             tputs ("Accept\n");
  410.     } else {
  411.         if (argv[1][0] == 'r')
  412.             Refuse_echo = 1;
  413.         else if (argv[1][0] == 'a')
  414.             Refuse_echo = 0;
  415.         else
  416.             return -1;
  417.     }
  418.     return 0;
  419. }
  420.  
  421.  
  422.  
  423. /* set for unix end of line for remote echo mode telnet */
  424. int
  425. doeol (int argc, char *argv[], void *p OPTIONAL)
  426. {
  427.     if (argc < 2) {
  428.         if (Tn_cr_mode)
  429.             tputs ("null\n");
  430.         else
  431.             tputs ("standard\n");
  432.     } else {
  433.         if (argv[1][0] == 'n')
  434.             Tn_cr_mode = 1;
  435.         else if (argv[1][0] == 's')
  436.             Tn_cr_mode = 0;
  437.         else {
  438.             tprintf ("Usage: %s [standard|null]\n", argv[0]);
  439.             return -1;
  440.         }
  441.     }
  442.     return 0;
  443. }
  444.  
  445.  
  446.  
  447. /* The guts of the actual Telnet protocol: negotiating options */
  448. void
  449. willopt (struct telnet *tn, int opt)
  450. {
  451. int ack;
  452.  
  453. #ifdef    DEBUG
  454.     tcmdprintf ("recv: will ");
  455.     if (uchar (opt) <= NOPTIONS)
  456.         tcmdprintf ("%s\n", T_options[opt]);
  457.     else
  458.         tcmdprintf ("%u\n", opt);
  459. #endif
  460.  
  461.     switch (uchar (opt)) {
  462.         case TN_TRANSMIT_BINARY:
  463.         case TN_ECHO:
  464.         case TN_SUPPRESS_GA:
  465.             if (tn->remote[uchar (opt)] == 1)
  466.                 return;    /* Already set, ignore to prevent loop */
  467.             if (uchar (opt) == TN_ECHO) {
  468.                 if (Refuse_echo) {
  469.                     /* User doesn't want to accept */
  470.                     ack = DONT;
  471.                     break;
  472.                 } else {
  473.                     /* Put tty into raw mode */
  474.                     tn->session->ttystate.edit = 0;
  475.                     tn->session->ttystate.echo = 0;
  476.                     (void) sockmode (tn->session->s, SOCK_BINARY);
  477.                     (void) sockmode (tn->session->input, SOCK_BINARY);
  478.                     (void) sockmode (tn->session->output, SOCK_BINARY);
  479.                     if (tn->session->record != NULLFILE)
  480.                         (void) filemode (tn->session->record, SOCK_BINARY);
  481.  
  482.                 }
  483.             }
  484.             tn->remote[uchar (opt)] = 1;
  485.             ack = DO;
  486.             break;
  487.         default:
  488.             ack = DONT;    /* We don't know what he's offering; refuse */
  489.     }
  490.     answer (tn, ack, opt);
  491. }
  492.  
  493.  
  494.  
  495. void
  496. wontopt (struct telnet *tn, int opt)
  497. {
  498. #ifdef    DEBUG
  499.     tcmdprintf ("recv: wont ");
  500.     if (uchar (opt) <= NOPTIONS)
  501.         tcmdprintf ("%s\n", T_options[uchar (opt)]);
  502.     else
  503.         tcmdprintf ("%u\n", uchar (opt));
  504. #endif
  505.     if (uchar (opt) <= NOPTIONS) {
  506.         if (tn->remote[uchar (opt)] == 0)
  507.             return;    /* Already clear, ignore to prevent loop */
  508.         tn->remote[uchar (opt)] = 0;
  509.         if (uchar (opt) == TN_ECHO) {
  510.             /* Put tty into cooked mode */
  511.             tn->session->ttystate.edit = 1;
  512.             tn->session->ttystate.echo = 1;
  513.             (void) sockmode (tn->session->s, SOCK_ASCII);
  514.             (void) sockmode (tn->session->input, SOCK_ASCII);
  515.             (void) sockmode (tn->session->output, SOCK_ASCII);
  516.             if (tn->session->record != NULLFILE)
  517.                 (void) filemode (tn->session->record, SOCK_ASCII);
  518.         }
  519.     }
  520.     answer (tn, DONT, opt);    /* Must always accept */
  521. }
  522.  
  523.  
  524.  
  525. static void
  526. doopt (struct telnet *tn, int opt)
  527. {
  528. int ack;
  529.  
  530. #ifdef    DEBUG
  531.     tcmdprintf ("recv: do ");
  532.     if (uchar (opt) <= NOPTIONS)
  533.         tcmdprintf ("%s\n", T_options[uchar (opt)]);
  534.     else
  535.         tcmdprintf ("%u\n", uchar (opt));
  536. #endif
  537.     switch (uchar (opt)) {
  538.         case TN_SUPPRESS_GA:
  539.             if (tn->local[uchar (opt)] == 1)
  540.                 return;    /* Already set, ignore to prevent loop */
  541.             tn->local[uchar (opt)] = 1;
  542.             ack = WILL;
  543.             break;
  544.         default:
  545.             ack = WONT;    /* Don't know what it is */
  546.     }
  547.     answer (tn, ack, opt);
  548. }
  549.  
  550.  
  551.  
  552. static void
  553. dontopt (struct telnet *tn, int opt)
  554. {
  555. #ifdef    DEBUG
  556.     tcmdprintf ("recv: dont ");
  557.     if (uchar (opt) <= NOPTIONS)
  558.         tcmdprintf ("%s\n", T_options[uchar (opt)]);
  559.     else
  560.         tcmdprintf ("%u\n", uchar (opt));
  561. #endif
  562.     if (uchar (opt) <= NOPTIONS) {
  563.         if (tn->local[uchar (opt)] == 0)    /* Already clear, ignore to prevent loop */
  564.             return;
  565.  
  566.         tn->local[uchar (opt)] = 0;
  567.     }
  568.     answer (tn, WONT, opt);
  569. }
  570.  
  571.  
  572.  
  573. static void
  574. answer (struct telnet *tn, int r1, int r2)
  575. {
  576. char s[3];
  577.  
  578. #ifdef    DEBUG
  579.     switch (r1) {
  580.         case WILL:
  581.             tcmdprintf ("sent: will ");
  582.             break;
  583.         case WONT:
  584.             tcmdprintf ("sent: wont ");
  585.             break;
  586.         case DO:
  587.             tcmdprintf ("sent: do ");
  588.             break;
  589.         case DONT:
  590.             tcmdprintf ("sent: dont ");
  591.             break;
  592.     }
  593.     if (r2 <= NOPTIONS)
  594.         tcmdprintf ("%s\n", T_options[r2]);
  595.     else
  596.         tcmdprintf ("%u\n", r2);
  597. #endif
  598.  
  599.     s[0] = (char) IAC;
  600.     s[1] = (char) r1;
  601.     s[2] = (char) r2;
  602.     (void) send (tn->session->s, s, 3, 0);
  603. }
  604.  
  605.  
  606.  
  607. static int
  608. filemode (FILE *fp OPTIONAL, int mode OPTIONAL)
  609. {
  610.     return 0;
  611. }
  612.  
  613.